package top.ibase4j.core.support.jsonfilter;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import top.ibase4j.core.base.BaseModel;

/**
 * 实现ResponseBodyAdvice接口，剔除不返回的字段或只返回特定字段
 * 
 * @author zhangchao
 *
 */
@SuppressWarnings("rawtypes")
@Order(1)
@ControllerAdvice(basePackages = "org.ibase4j.web")
public class MyResponseBodyAdvice implements ResponseBodyAdvice {
	// 包含项
	private String[] includes = {};
	// 排除项
	private String[] excludes = {};

	@Override
	public boolean supports(MethodParameter methodParameter, Class aClass) {
		// 这里可以根据自己的需求，如果有些接口controller不走这里就可以在这里进行判断
		if (methodParameter.getMethod().isAnnotationPresent(UnSerializedField.class)) {
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass,
			ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
		// 重新初始化为默认值
		includes = new String[] {};
		excludes = new String[] {};

		// 判断返回的对象是单个对象，还是list，活着是map
		if (o == null) {
			return null;
		}
		if (methodParameter.getMethod().isAnnotationPresent(SerializedField.class)) {
			// 获取注解配置的包含和去除字段
			SerializedField serializedField = methodParameter.getMethodAnnotation(SerializedField.class);
			includes = serializedField.includes();
			excludes = serializedField.excludes();

		}
		Object retObj = null;
		if (o instanceof Map) {
			Map r = (Map) o;
			Object data = r.get("data");
			if (data != null) {
				if (data instanceof List) {
					// List
					List list = (List) data;
					retObj = handleList(list);
				} else if (data instanceof Map) {
					Map<String, Object> m = (Map) data;
					retObj = handleMap(m);
				} else if (data instanceof String || data instanceof Integer || data instanceof Double
						|| data instanceof Long || data instanceof Date || data instanceof Boolean
						|| data instanceof java.sql.Date || data instanceof Float) {
					retObj = data;
					// 这是基本类型，就不做处理了
				} else if (data instanceof BigDecimal) {
					retObj = data == null ? 0 : Double.parseDouble(data.toString());
				} else {
					// Single Object
					retObj = handleSingleObject(data);
				}
				r.put("data", retObj);
				return r;
			}
			return r;
		} else {
			if (o instanceof List) {
				// List
				List list = (List) o;
				retObj = handleList(list);
			} else {
				// Single Object
				retObj = handleSingleObject(o);
			}
			return retObj;
		}
	}

	/**
	 * 处理返回值是单个enity对象
	 *
	 * @param o
	 * @return
	 */
	private Object handleSingleObject(Object o) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (o == null) {
			return map;
		}
		Field[] addAll = null;
		Field[] fields = o.getClass().getDeclaredFields();
		if (o instanceof BaseModel) {
			Field[] declaredFields = o.getClass().getSuperclass().getDeclaredFields();
			addAll = (Field[]) ArrayUtils.addAll(fields, declaredFields);
		} else {
			addAll = fields;
		}
		for (Field field : addAll) {
			// 如果未配置表示全部的都返回
			if (includes.length == 0 && excludes.length == 0) {
				Object newVal = getNewVal(o, field);
				map.put(field.getName(), newVal);
			} else if (includes.length > 0) {
				// 有限考虑包含字段
				if (isStringInArray(field.getName(), includes)) {
					Object newVal = getNewVal(o, field);
					map.put(field.getName(), newVal);
				}
			} else {
				// 去除字段
				if (excludes.length > 0) {
					if (!isStringInArray(field.getName(), excludes)) {
						Object newVal = getNewVal(o, field);
						map.put(field.getName(), newVal);
					}
				}
			}

		}
		return map;
	}

	/**
	 * 处理返回值是列表
	 *
	 * @param list
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List handleList(List list) {
		List retList = new ArrayList();
		if (list == null) {
			return retList;
		}
		for (Object o : list) {
			Map map = (Map) handleSingleObject(o);
			retList.add(map);
		}
		return retList;
	}

	/**
	 * 处理返回值是map集合
	 *
	 * @param Map
	 * @return
	 */
	private Map handleMap(Map<String, Object> data) {
		if (data == null) {
			return data;
		}
		for (Map.Entry<String, Object> entry : data.entrySet()) {
			Object value = entry.getValue();
			if (value instanceof List) {
				// List
				List list = (List) value;
			} else if (value instanceof String || value instanceof Integer || value instanceof Double
					|| value instanceof Long || value instanceof Date || value instanceof Boolean
					|| value instanceof java.sql.Date || value instanceof Float) {
				entry.setValue(value);
			} else if (data instanceof BigDecimal) {
				entry.setValue(data == null ? 0D : Double.parseDouble(data.toString()));
			} else {
				// Single Object
				entry.setValue(handleSingleObject(value));
			}
		}
		return data;
	}

	/**
	 * 这里可以添加加密操作
	 *
	 * @param o
	 * @param field
	 * @return
	 */
	private Object getNewVal(Object o, Field field) {
		Object val = null;
		try {
			field.setAccessible(true);
			val = field.get(o);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		return val;
	}

	/**
	 * 判断字段是否该剔除
	 * 
	 * @param str
	 * @param array
	 * @return
	 */
	public static boolean isStringInArray(String str, String[] array) {
		for (String val : array) {
			if (str.equals(val) || str.equals("serialVersionUID")) {
				return true;
			}
		}
		return false;
	}

}
